import { launch, Browser, Page } from 'puppeteer';
import SystemManager from './systemManager';

// 全局监听了错误 这里就不再细化处理了


export default class PuppeteerManager {
    static instance;
    static getInstance() {
        if (this.instance == null) {
            this.instance = new PuppeteerManager();
        }
        return this.instance;
    }

    selfConf = {
        headless: false,
        fullPage: true,
        page: 1,
        total: 1
    }

    crawlerConf: CrawlerInitConf;
    browser: Browser;
    page: Page;
    activePage: Page;

    // 数据池可以定义为自己需要的内容
    dataPool: any[];
    sessionMap: Record<string, any>

    todoUrls = [];
    todoLists = [];

    constructor() {
        this.crawlerConf = {
            url: "",
            search: " ",
            type: '1',
            pagesEntry: "",
            pageMethod: '1',
            totalEntry: "",
            imgEntry: "",
            nameEntry: "",
            idEntry: "",
            appName: "",
            useHeadless: "2",
            clickEls: ""
        }
    }

    async init(conf: CrawlerInitConf) {
        // 更新爬虫指定配置
        Object.assign(this.crawlerConf, { ...conf });
        // 重置通用配置
        Object.assign(this.selfConf, { page: 1, total: 1 });

        this.browser = await launch({ headless: conf.useHeadless === '1' });
        this.page = await this.browser.newPage();

        // 是否全屏
        await this.page.setViewport({ width: 1920, height: 1080 });
        // 是否需要注册新建窗口事件
        await (conf.type === '2') && this.registerPageCreateEvent();
        // 跳转页面
        await conf.url && this.page.goto(`${conf.url}${(conf.search || '').replace('$$', this.selfConf.page.toString())}`)
        // 跳转到指定的抓取位置
        await this.gotoGrabPosition();

    }

    async gotoGrabPosition() {
        // 点击步骤
        const clickSteps = this.crawlerConf.clickEls.split("&&&");
        while (clickSteps.length > 1) {
            let handleStep = clickSteps.shift();
            console.log(handleStep, '需要点击的是');
            await this.page.waitForSelector(handleStep);
            await this.page.click(handleStep);
        }

        process.nextTick(async () => {
            // 获取总页数
            await this.initPageTotal();
            // 开始收集
            await this.extractCurrentPage();
        })
    }


    async initPageTotal() {
        let [totalStr, code] = this.crawlerConf.totalEntry.split('&&&');
        if (totalStr && code) {
            await this.page.waitForSelector(totalStr);
            let document = await this.page.$('body');
            this.selfConf.total = +(await document?.evaluate((e: any, ad) => {
                let [totalStr, code] = ad.split('&&&');
                return eval(`document.querySelector('${totalStr}')${code}`);
            }, this.crawlerConf.totalEntry)) || 1;
        }
    }

    async registerPageCreateEvent() {
        this.browser.on('targetcreated', async (target) => {
            if (target.type() === 'page') {
                let page = await target.page();
                if (page == null) return;
                this.activePage?.close();
                this.activePage = page;
            }
        })
    }

    // 获取当前页面的跳转
    async collectSelfNavigateData() {

    }

    // 获取新窗口的跳转
    async collectBlankNavigateData() {

    }

    async extractCurrentPage() {
        if (this.selfConf.page >= this.selfConf.total) {
            this.page.close();
            this.browser.close();
            console.log('dnone', this.selfConf);
            return;
        };
        await this.page.waitForSelector(this.crawlerConf.pagesEntry);
        const links = await this.page.$$(this.crawlerConf.pagesEntry);
        if (links.length) {
            let idx = 1;
            for await (let item of links) {
                let basic = await item.evaluate(async (rl: any, ad: string) => {
                    let [app, idStr, imgStr, nameStr, el] = ad.split('||'),
                        [idEl, codeId] = idStr.split('&&&'),
                        [nameEl, codeName] = nameStr.split('&&&'),
                        [imgEl, codeImg] = imgStr.split('&&&');
                    let id = eval(`document.querySelector('${el} ${idEl}')${codeId}`);
                    return await {
                        fr: `${app}_${id}`,
                        id: Date.now(),
                        el,
                        nm: eval(`document.querySelector('${el} ${nameEl}')${codeName}`),
                        image: eval(`document.querySelector('${el} ${imgEl}')${codeImg}`),
                        // !todo 可自定义添加要收集的内容
                        url: ''
                    };
                }, `${this.crawlerConf.appName}||${this.crawlerConf.idEntry}||${this.crawlerConf.imgEntry}||${this.crawlerConf.nameEntry}||${this.crawlerConf.pagesEntry}:nth-child(${idx})`)

                idx++;

                SystemManager.getInstance().sendMessageToRender('captureInfo', basic);
            }

            setTimeout(() => {
                switch (this.crawlerConf.pageMethod) {
                    case "1": {
                        return this.addSelfToNextPage()

                    }
                    case "2": {
                        return this.scrollToNextPage()

                    }
                    case "3": {
                        return this.clickToNextPage()
                    }
                }
            }, 1500)
        }
    }

    // go to nextPage methods 1
    async clickToNextPage() {
        if (!this.crawlerConf.clickEls) {
            this.stopTask();
            return;
        }
        let nextPageEl = this.crawlerConf.clickEls.split('&&&').pop();
        console.log('下一页按钮', nextPageEl);
        await this.page.waitForSelector(nextPageEl);
        await this.page.click(nextPageEl);
        this.selfConf.page += 1;
        await this.extractCurrentPage();
    }

    // go to nextPage methods 2
    async addSelfToNextPage() {
        this.selfConf.page += 1;
        await this.page.goto(`${this.crawlerConf.url}${(this.crawlerConf.search || '').replace('$$', (this.selfConf.page).toString())}`);
        await this.extractCurrentPage();
    }

    // go to nextPage methods 3
    async scrollToNextPage() {

    }


    getData() {
        return this.dataPool;
    }

    stopTask() {
        this.page && this.page.close();
        this.browser && this.browser.close();
        this.page = null;
        this.browser = null;
    }

    test() {

    }
}